﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SiKuma.ScreenSystemLibrary
{
    public abstract class MenuScreen : GameScreen
    {
        private List<MenuEntry> menuEntries = new List<MenuEntry>();
        private bool mouseVisible;
        private float titleOpacity = 1f;
        private Color highlighted = Color.White;
        private Color selected = Color.White;
        private Color normal = Color.White;
        private Texture2D descriptionTexture;
        private Color descriptionColor;
        private Color descriptionBoxColor;
        private float descriptionScale;
        private int selectedEntry;
        
        public event EventHandler Cancel;
        
        public GameScreen Parent
        {
            get;
            set;
        }
        
        public List<MenuEntry> MenuEntries
        {
            get
            {
                return this.menuEntries;
            }
        }
        
        public SpriteFont SpriteFont
        {
            get;
            set;
        }
        
        public Texture2D BackgroundTexture
        {
            get;
            set;
        }
        
        public Vector2 BackgroundPosition
        {
            get;
            set;
        }
        
        public Texture2D TitleTexture
        {
            get;
            set;
        }
        
        public Vector2 InitialTitlePosition
        {
            get;
            set;
        }
        
        public Vector2 TitlePosition
        {
            get;
            set;
        }
        
        public Texture2D MouseTexture
        {
            get;
            set;
        }
        
        public Rectangle MouseBounds
        {
            get;
            private set;
        }
        
        public float TitleOpacity
        {
            get
            {
                return this.titleOpacity;
            }
            set
            {
                this.titleOpacity = value;
            }
        }
        
        public Vector2 Position
        {
            get;
            set;
        }
        
        public Color Highlighted
        {
            get
            {
                return this.highlighted;
            }
            set
            {
                this.highlighted = value;
            }
        }
        
        public Color Selected
        {
            get
            {
                return this.selected;
            }
            set
            {
                this.selected = value;
            }
        }
        
        public Color Normal
        {
            get
            {
                return this.normal;
            }
            set
            {
                this.normal = value;
            }
        }
        
        public Rectangle DescriptionPosition
        {
            get;
            private set;
        }
        
        public Point DescriptionPadding
        {
            get;
            set;
        }
        
        public abstract string PreviousEntryActionName
        {
            get;
        }
        
        public abstract string NextEntryActionName
        {
            get;
        }
        
        public abstract string SelectedEntryActionName
        {
            get;
        }
        
        public abstract string MenuCancelActionName
        {
            get;
        }
        
        public override bool AcceptsInput
        {
            get
            {
                return true;
            }
        }
        
        public virtual void MenuCancel()
        {
            base.ExitScreen();
            if (this.Cancel != null)
            {
                this.Cancel(this, EventArgs.Empty);
            }
        }
        
        protected MenuScreen()
        {
            base.Removing += new EventHandler(this.MenuScreen_Removing);
        }
        
        public abstract override void InitializeScreen();
        public abstract override void LoadContent();
        
        protected override void UpdateScreen(GameTime gameTime)
        {
            if (this.menuEntries.Count == 0)
            {
                return;
            }
            if (this.menuEntries[this.selectedEntry].State != MenuEntry.EntryState.Highlight)
            {
                this.menuEntries[this.selectedEntry].Highlight();
            }
            for (int i = 0; i < this.menuEntries.Count; i++)
            {
                this.menuEntries[i].UpdateEntry(gameTime);
                this.menuEntries[this.selectedEntry].AnimateHighlighted(gameTime);
            }
            if (this.MouseTexture != null)
            {
                Vector2 mousePosition = base.InputMap.GetMousePosition();
                this.MouseBounds = new Rectangle((int)mousePosition.X, (int)mousePosition.Y, this.MouseTexture.Width, this.MouseTexture.Height);
            }
        }
        
        private void MenuScreen_Removing(object sender, EventArgs e)
        {
            this.menuEntries.Clear();
            if (this.Parent != null && this.Parent.State == ScreenState.Frozen)
            {
                this.Parent.ActivateScreen();
                MenuScreen menuScreen = this.Parent as MenuScreen;
                if (menuScreen != null && menuScreen.MouseTexture != null)
                {
                    menuScreen.ShowMouse();
                }
            }
        }
        
        public override void HandleInput()
        {
            if (base.InputMap.NewActionPress(this.PreviousEntryActionName))
            {
                this.menuEntries[this.selectedEntry].Normal();
                this.selectedEntry--;
                if (this.selectedEntry < 0)
                {
                    this.selectedEntry = this.menuEntries.Count - 1;
                }
                this.menuEntries[this.selectedEntry].Highlight();
            }
            if (base.InputMap.NewActionPress(this.NextEntryActionName))
            {
                this.menuEntries[this.selectedEntry].Normal();
                this.selectedEntry++;
                if (this.selectedEntry >= this.menuEntries.Count)
                {
                    this.selectedEntry = 0;
                }
                this.menuEntries[this.selectedEntry].Highlight();
            }
            if (this.MouseTexture != null && this.mouseVisible)
            {
                for (int i = this.menuEntries.Count - 1; i >= 0; i--)
                {
                    if (this.menuEntries[i].BoundingRectangle.Intersects(this.MouseBounds))
                    {
                        this.menuEntries[this.selectedEntry].Normal();
                        this.selectedEntry = i;
                        this.menuEntries[this.selectedEntry].Highlight();
                    }
                }
            }
            if (base.InputMap.NewActionPress(this.SelectedEntryActionName))
            {
                this.menuEntries[this.selectedEntry].Select();
            }
            if (base.InputMap.NewActionPress(this.MenuCancelActionName))
            {
                this.MenuCancel();
            }
        }
        
        protected override void DrawScreen(GameTime gameTime)
        {
            SpriteBatch spriteBatch = base.ScreenSystem.SpriteBatch;
            if (this.BackgroundTexture != null)
            {
                spriteBatch.Draw(this.BackgroundTexture, this.BackgroundPosition, Color.White);
            }
            if (this.TitleTexture != null)
            {
                spriteBatch.Draw(this.TitleTexture, this.TitlePosition, Color.White * this.titleOpacity);
            }
            for (int i = 0; i < this.menuEntries.Count; i++)
            {
                this.menuEntries[i].Draw(gameTime, i == this.selectedEntry);
            }
            this.DrawDescriptionArea(spriteBatch, gameTime);
            this.DrawMouse(spriteBatch, gameTime);
        }
        
        private void DrawDescriptionArea(SpriteBatch spriteBatch, GameTime gameTime)
        {
            string entryDescription = this.menuEntries[this.selectedEntry].EntryDescription;
            if (!string.IsNullOrEmpty(entryDescription) && this.descriptionTexture != null)
            {
                spriteBatch.Draw(this.descriptionTexture, this.DescriptionPosition, this.descriptionBoxColor);
                this.menuEntries[this.selectedEntry].DrawDescription(gameTime, this.DescriptionPosition, this.DescriptionPadding, this.descriptionColor, this.descriptionScale);
            }
        }
        
        private void DrawMouse(SpriteBatch spriteBatch, GameTime gameTime)
        {
            if (this.MouseTexture != null && this.mouseVisible)
            {
                spriteBatch.Draw(this.MouseTexture, base.InputMap.GetMousePosition(), Color.White);
            }
        }
        
        public void SetDescriptionArea(Rectangle position, Color boxColor, Color TextColor, float scale)
        {
            this.SetDescriptionArea(position, boxColor, TextColor, new Point(0, 0), scale);
        }
        
        public void SetDescriptionArea(Rectangle position, Color boxColor, Color TextColor, Point padding, float scale)
        {
            this.DescriptionPosition = position;
            this.descriptionTexture = new Texture2D(base.ScreenSystem.GraphicsDevice, 1, 1);
            Color[] data = new Color[]
			{
				boxColor
			};
            this.descriptionTexture.SetData<Color>(data);
            this.descriptionBoxColor = boxColor;
            this.descriptionColor = TextColor;
            this.DescriptionPadding = padding;
            this.descriptionScale = scale;
        }
        
        public void EnableMouse(Texture2D texture)
        {
            if (texture != null)
            {
                this.MouseTexture = texture;
                this.mouseVisible = true;
            }
        }
        
        public void ShowMouse()
        {
            this.mouseVisible = true;
        }
        
        public void HideMouse()
        {
            this.mouseVisible = false;
        }
    }
}
